<!--
 * @Author: DaHuaZhuXi
 * @Date: 2020-10-13 16:42:13
 * @LastEditTime: 2021-01-14 14:40:33
 * @LastEditors: DaHuaZhuXi
 * @Description: 战场

攻击流程：doAction() 执行动作 -> animate.start() 先执行动画 -> doOneAction() 执行并计算 ->
animateCallBack()动画结束回调，关闭动画遮罩 -> doAction的callBack动作回调 

-->

<template>
  <div components="Battle" class="battle">
    <!-- 顶部状态条 -->
    <div class="topBar" :class="round % 2 == 0 ? 'enemyRound' : ''">
      <span class="round"
        >第{{ round }}回合 [ {{ round % 2 == 0 ? '敌方' : '我方' }} ]</span
      >
    </div>
    <!-- 当前人员状态 -->
    <PeoStatus v-if="curPeo" :peo="curPeo"></PeoStatus>
    <div id="mapWrap">
      <div id="mapDrag" style="transform: translate3d(0px, 0px, 0px)">
        <div id="mapIn">
          <!-- 地图 -->
          <canvas id="map"></canvas>
          <!-- 地图上的元素 -->
          <Elements :datas="elements" :curPeo="curPeo" :unitSize="unitSize"></Elements>
          <!-- 敌人 -->
          <ul class="peos enemys">
            <li
              v-for="peo in enemys"
              :key="peo.id"
              :id="peo.id"
              :class="[
                curPeo == peo ? 'active' : '',
                peo._state == 'end' ? 'end' : '',
              ]"
              :style="{
                width: unitSize + 'px',
                height: unitSize + 'px',
                left: unitSize * peo.x + 'px',
                top: unitSize * peo.y + 'px',
              }"
            >
              <Peo
                :peo="peo"
                :style="{
                  fontSize: unitSize + 'px',
                  lineHeight: unitSize - 8 + 'px',
                }"
              ></Peo>
              <span
                class="hit"
                v-if="
                  curPeo &&
                  common.indexOf2Array([peo.x, peo.y], curPeo._actionRange) !=
                    -1
                "
                >{{ curPeo.hit - peo.eva + '%' }}</span
              >
            </li>
          </ul>
          <!-- 我方人员 -->
          <ul class="peos myTeam">
            <li
              v-for="peo in peos"
              :key="peo.id"
              :id="peo.id"
              :class="[
                curPeo == peo ? 'active' : '',
                peo._state == 'end' ? 'end' : '',
              ]"
              :style="{
                width: unitSize + 'px',
                height: unitSize + 'px',
                left: unitSize * peo.x + 'px',
                top: unitSize * peo.y + 'px',
              }"
            >
              <Peo
                :peo="peo"
                :style="{
                  fontSize: unitSize + 'px',
                  lineHeight: unitSize - 8 + 'px',
                }"
              ></Peo>
            </li>
          </ul>
          <!-- 地图覆盖层，用于地图交互 -->
          <section id="mapMask" @touchstart.stop="click_map($event)"></section>
        </div>
      </div>
    </div>

    <!-- 技能 -->
    <div class="skills">
      <ul v-if="curPeo">
        <li
          v-for="skill in curPeo._skills"
          :key="skill.id"
          @click="click_skill(skill)"
          :class="curSkill == skill ? 'cur' : ''"
          :style="{
            width: unitSize + 'px',
            height: unitSize + 'px',
            fontSize: unitSize + 'px',
            lineHeight: unitSize + 'px',
          }"
        >
          <div
            :class="[
              'in',
              skillClass(skill)
            ]"
          >
            <span class="peoAP">
              <i v-for="(i, index) in skill.ap" :key="index"><s></s></i>
            </span>
            <span class="name">{{ skill.type }}</span>
          </div>
        </li>
      </ul>
    </div>

    <!-- 底部按钮 -->
    <BottomBtns
      :curPeo="curPeo"
      :round="round"
      @click_cancle="click_cancle"
      @click_end="click_end"
    ></BottomBtns>
    <FooterNav></FooterNav>

    <!-- 透明遮罩层（用于执行行动动画时，页面所有元素不能交互） -->
    <div id="animateMask"></div>
  </div>
</template>

<script>
import Peo from '@/components/Peo.vue';
import BottomBtns from './components/BottomBtns.vue';
import Elements from './components/Elements.vue';
import PeoStatus from '@/views/MyTeam/components/PeoStatus.vue';
import Map from "@/class/Map.js";
import { getPointUnit } from "@/class/Tool.js";
import { getMovePath } from "@/class/tool/AStar.js";
import * as Battle from "./code/Battle.js";
import AI from './code/AI.js';
export default {
  components: { Peo, PeoStatus, BottomBtns, Elements },
  data() {
    return {
      peos: [], //我方人员
      enemys: [], //临时生成敌人
      elements: [], //临时生成的地图上的元素（障碍物等）
      curPeo: null, //当前人员
      unitSize: 0, //地图单位尺寸
      skills: [], //当前人员所主动技能
      curSkill: null, //当前技能
      round: 0, //当前回合，单数我方，双数敌方
      useAp: 0, //当前技能将消耗ap数
    }
  },
  created() {
    this.placeId = this.$store.state.maze.placeId; //地点id

    this.tempPeos = []; //存储结算用的我方成员，因为peos的人员会被删除
    this.tempEnemys = []; //存储结算用的敌方成员，因为enemys的人员会被删除
    //this.enemyGoods = []; //存储临时生成的敌人装备，用于结算奖励
    this.mapDiv = config.battleMapSize; //横向屏幕划分多少份
    this.mapSize = { xMax: this.mapDiv - 1, yMax: this.mapDiv - 1 };
    this.map = new Map;
    Battle.initPeos.call(this);
    Battle.initEnemys.call(this);
    Battle.initElements.call(this); //初始化地图元素（障碍物等）
  },
  mounted() {
    this.$map = document.getElementById("map");
    Battle.initMap.call(this);

    this.AI = new AI({
      enemys: this.enemys,
      peos: this.peos,
      elements: this.elements,
      map: this.map,
    });
    console.log(this.tempPeos, this.tempEnemys);
    //this.$router.push({ name: 'BattleEnd', params: { winner:1, peos: this.tempPeos, enemys:this.tempEnemys } })
    this.nextRound();
  },
  computed: {
    // 技能css类名称
    skillClass() {
      return function(skill) {
        const result = this.curPeo._state == 'end' || this.curPeo._ap < skill.ap || (skill.ap > this.curPeo._ap - this.useAp) ? 'disabled' : '';
        return result;
      }
    }
  },
  methods: {
    //点击技能
    click_skill(skill) {
      this.curPeo.cancle();
      if (this.curPeo._state == "end" || this.curPeo._ap < skill.ap) return;
      this.curSkill = skill;
      this.curPeo.updateAbility(skill);
      if (skill.id == -1) {
        this.useAp = 0;
        this.curPeo.creatMoveRange();
      } else {
        this.useAp = this.curSkill.ap;
        if (skill.rangeID == 0) { //自身使用技能
          this.curPeo.doAction([this.curPeo.x, this.curPeo.y], this.curSkill, this.useAp, this.actionCallBack)
        } else {
          this.curPeo.creatSkillRange(skill);
        }
      }
    },

    //地图点击事件
    click_map(e) {
      //敌方回合点击无效
      if (this.round % 2 == 0) return;
      let point = common.getMapPoint(e, this.unitSize, document.getElementById("mapWrap"));
      let unit = getPointUnit(point, this.peos, this.elements, this.enemys);
      //console.log("点击坐标：", point, "坐标单位：", unit);

      //已有人员激活
      if (this.curPeo) {
        //如果是移动状态
        if (this.curPeo._state == "moveRange") {
          //如果点击移动范围内的点
          if (common.indexOf2Array(point, this.curPeo._moveRange) != -1) {
            //如果是当前激活的是敌人则无效
            if (this.curPeo._type == "enemy") return;

            //如果存在移动路径，并且终点和当前用户点击点一致，则执行移动
            let movePath = this.curPeo._movePath;
            if (movePath && common.indexOf2Array(movePath[movePath.length - 1], [point]) != -1) {
              this.curPeo.doAction(point, this.curSkill, this.useAp, this.actionCallBack);
            }
            //否则生成移动范围和寻路路径
            else {
              let movePath = getMovePath({ map: this.map, start: [this.curPeo.x, this.curPeo.y], end: point });
              this.curPeo._movePath = movePath;
              this.useAp = this.curSkill.ap * movePath.length;
              this.curPeo.creatMoveRange(movePath);
            }
          } else {
            this.resetMoveSkillAp();
            this.checkUnit(unit);
          }
        }
        //如果是行动状态
        else {
          //如果在动作范围内
          if (common.indexOf2Array(point, this.curPeo._actionRange) != -1) {
            //如果当前控制的是敌人则无效
            if (this.curPeo._type == "enemy") return;
            this.curPeo.doAction(point, this.curSkill, this.useAp, this.actionCallBack)
          } else {
            this.checkUnit(unit);
          }
        }
      } else {
        //没有人员激活
        this.checkUnit(unit)
      }

    },

    //执行动作后的回调事件
    actionCallBack() {
      this.resetMoveSkillAp();
      if (!this.isGameOver()) {
        this.setEnd(this.peos);
        if (this.isRoundEnd(this.peos)) {
          this.nextRound()
        } else {
          // 如果当前人物行动没结束则默认触发上一次技能（完善体验）
          // if (this.curSkill && this.curSkill.id != 99) {
          //   this.click_skill(this.curSkill);
          // }
        }
      }
    },

    //根据当前Ap情况自动结束自身回合
    setEnd(ary) {
      ary.forEach(peo => {
        let end = true;
        for (let i = 0; i < peo._skills.length - 1; i++) {
          if (peo._ap > 0 && peo._skills[i].ap <= peo._ap) {
            end = false;
            break;
          }
        }
        peo._state = end ? "end" : peo._state;
      })
    },

    //删除阵亡单位
    removeDieUnit(ary) {
      for (let i = ary.length - 1; i >= 0; i--) {
        if (ary[i].hp <= 0) {
          ary.splice(i, 1);
          this.map.updateBanPoints(this.peos, this.elements, this.enemys);
        }
      }
    },

    //是否游戏结束
    isGameOver() {
      this.removeDieUnit(this.peos);
      this.removeDieUnit(this.enemys);
      this.removeDieUnit(this.elements);
      if (this.peos.length > 0 && this.enemys.length > 0) return;
      let winner = this.peos.length == 0 ? 2 : 1;
      let str = winner == 1 ? "战斗结束，我方胜利" : "战斗结束，我方失败";
      this.$dialog.alert({
        message: str,
      }).then(() => {
        this.$router.push({ name: 'BattleEnd', params: { winner: winner, peos: this.tempPeos, enemys: this.tempEnemys } })
      });
      return true;
    },

    //检测点击点是否存在单位
    checkUnit(unit) {
      if (unit) {
        this.click_unit(unit)
      } else {
        this.click_cancle()
      }
    },

    //检测点击点是否存在单位
    resetMoveSkillAp() {
      this.useAp = 0;
    },

    //点击单位
    click_unit(unit) {
      if (unit._type == "our" || unit._type == "enemy") {
        this.curPeo = unit;
        this.click_skill(this.curPeo._skills[0]);
        unit.creatMoveRange();
      } else {
        this.click_cancle()
      }
    },

    //下一回合
    nextRound() {
      this.round++;
      console.warn("第" + this.round + "回合，" + (this.round % 2 == 0 ? "敌方" : "我方") + "开始");
      //敌方
      if (this.round % 2 == 0) { 
        this.resetStatusAndExecuteBuffs(this.enemys)
        this.AI.start(this.enemys[0], this.isGameOver, () => {
          this.aiEndCallBack(0)
        });
      }
      //我方
      else {
        this.resetStatusAndExecuteBuffs(this.peos);
      }
    },

    //ai回调
    aiEndCallBack(i) {
      i++;
      if (this.isRoundEnd(this.enemys)) {
        this.nextRound();
        return;
      }
      this.AI.start(this.enemys[i], this.isGameOver, () => {
        this.aiEndCallBack(i)
      });
    },

    //检查是否回合结束
    isRoundEnd(ary) {
      let count = ary.length;
      ary.forEach(peo => {
        if (peo._state == "end") {
          count--;
        }
      });
      return count <= 0
    },

    //重置ap和状态 -> 执行buff -> 监测是否gameover
    resetStatusAndExecuteBuffs(units) {
      units.forEach(unit => {
        unit.resetStatus();
        unit.executeBuffs();
      });
      this.isGameOver();
    },

    //点击取消按钮
    click_cancle() {
      if (this.curPeo) {
        this.curPeo.cancle();
        this.curPeo = null;
      }
      this.curSkill = null;
      this.skills = [];
    },

    //点击结束回合按钮
    click_end() {
      this.peos.forEach(peo => {
        peo.action_end()
      })
      this.click_cancle();
      this.nextRound();
    },

  },
  beforeDestroy() { }
}
</script>

<style lang="scss">
.battle {
  height: 100%;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;

  .topBar {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    font-size: 12px;
    height: 18px;
    line-height: 18px;
    border-top: 4px #0077aa solid;

    .round {
      display: inline-block;
      background: #0077aa;
      padding: 0 10px;
      border-radius: 0 0 5px 5px;
    }
  }

  .topBar.enemyRound {
    border-top-color: #aa0000;

    .round {
      background: #aa0000;
    }
  }

  #mapIn {
    position: relative;
  }

  #map {
    display: block;
  }

  #mapMask {
    position: absolute;
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;
  }

  .peos {
    > li {
      display: inline-block;
      position: absolute;
      opacity: 1;
      transform: rotate(0deg) scale(1, 1);

      .name {
        display: none;
      }
    }

    .peo {
      background: #0077aa;
    }

    .active {
      background: #f60;
    }

    .end {
      .peo .mask {
        display: block;
      }
    }

    .hit {
      font-size: 0.4em;
      position: absolute;
      left: 0;
      right: 0;
      top: 31%;
      //text-shadow: 1px 1px 0 #000;
    }
  }

  .enemys .peo {
    background: #aa0000;
  }

  // .enemys .peoAP {
  //   //display: none;
  // }

  .PeoStatus {
    position: absolute;
    top: 15px;
    right: 10px;
    left: 10px;

    .infoTop {
      padding-bottom: 5px;
    }
  }

  .skills {
    position: absolute;
    left: 0;
    bottom: 97px;
    right: 0;

    li {
      display: inline-block;
      position: relative;
      vertical-align: top;

      .in {
        position: absolute;
        left: 2px;
        right: 2px;
        top: 2px;
        bottom: 2px;
        background: #0077aa;
        line-height: 0.5em;
        border-radius: 5px;
      }

      .peoAP {
        bottom: 3px;
        opacity: 0.5;

        s {
          background: #fff;
        }
      }

      .name {
        font-size: 12px;
      }

      .disabled {
        background: #666;
      }
    }

    .cur .in {
      background: #ff6600 !important;
    }
  }

  .peoAP {
    position: absolute;
    height: 4px;
    bottom: -4px;
    left: 0;
    right: 0;
    font-size: 0;

    i {
      vertical-align: top;
      display: inline-block;
      background: #ccc;
      width: 4px;
      height: 4px;
      margin: 0 1px;
      border-radius: 10px;
      overflow: hidden;
    }

    s {
      display: block;
      width: 100%;
      height: 100%;
      background: #55a532;
    }
  }

  #animateMask {
    display: none;
    z-index: 99;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0);
  }
}
</style>
